#include "Scene.h"

#include <algorithm>

// Renderer.
#include "Renderer.h"
#include "Camera.h"

// GameEngine.
#include "Material.h"
#include "Visual.h"

// CorLib.
#include "LeAssert.h"

// GLM.
#include <gtc/type_ptr.hpp>

le::Scene::Scene()
{

}

le::Scene::~Scene()
{
	LE_ASSERT(m_AttachedVisuals.size() == 0, "Deleting the scene while there are still objects (%i) attached to the scene! Memory leak?", m_AttachedVisuals.size());
	m_AttachedVisuals.clear();
}

void le::Scene::AttachVisual( le::Visual* visual )
{
	std::vector<le::Visual*>::iterator visualLocation = std::find(m_AttachedVisuals.begin(), m_AttachedVisuals.end(), visual);
	LE_ASSERT(visualLocation == m_AttachedVisuals.end(), "Attaching a visual that is already attached to the scene!");
	m_AttachedVisuals.push_back(visual);
}

void le::Scene::DetachVisual( le::Visual* visual )
{
	std::vector<le::Visual*>::iterator visualLocation = std::find(m_AttachedVisuals.begin(), m_AttachedVisuals.end(), visual);
	LE_ASSERT(visualLocation != m_AttachedVisuals.end(), "Detaching a visual that isn't attached to the scene!");
	if (visualLocation != m_AttachedVisuals.end())
	{
		m_AttachedVisuals.erase(visualLocation);
	}
}

void le::Scene::Render(le::Renderer* renderer)
{
	le::Camera* camera = renderer->GetActiveCamera();

	// Naive implementation - RENDER EVERYTHING!
	const size_t numVisuals = m_AttachedVisuals.size();
	for (size_t i = 0; i < numVisuals; ++i)
	{
		le::Visual* visual = m_AttachedVisuals[i];

		// Make the material the active material
		le::Material* material = visual->GetMaterial();
		renderer->MakeShaderActive(material->GetShaderProgramNumber());

		// Set the needed variables
		material->SetShaderVariable("worldMatrix", glm::value_ptr(visual->GetWorldMatrix()));
		material->SetShaderVariable("viewMatrix", glm::value_ptr(camera->GetViewMatrix()));
		material->SetShaderVariable("projectionMatrix", glm::value_ptr(camera->GetProjectionMatrix()));

		std::vector<le::Model*> models = visual->GetModels();
		const size_t numModels = models.size();
		for (size_t j = 0; j < numModels; ++j)
		{
			renderer->RenderModel(visual->GetModels()[j]);
		}
	}
}
